<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <!-- https://juejin.cn/post/7079807948830015502 -->
    <script>
        // 验证更新是否触发
        function updateView() {
            console.log('视图更新')
        }
        // 重新定义属性，监听起来
        function defineReactive(target, key, value) {
            Object.defineProperty(target, key, {
                get() {
                    return value
                },
                set(newVal) {
                    // value 一直在闭包中，此处设置完成后，下次get能够获取最新设置的值
                    // 这里有个小优化，若相同则不触发更新
                    if (newVal !== value) {
                        value = newVal
                        // 触发更新
                        updateView()
                    }
                }
            })
        }

        // 监听对象属性
        function observe(target) {
            if (typeof target !== 'object' || target === null) {
                // 不是数组或对象不适合监听
                console.log('不是数组或对象不适合监听');
                return target
            }
            // 将对象的属性用 defineProperty 重新定义
            for (let key in target) {
                defineReactive(target, key, target[key])
            }
        }

        // 准备数据
        const data = {
            name: 'Yimwu',
            id: 001,
            information: {
                tel: '135xxxxx354',
                email: '15xxxxx@xx.com'
            }
        }

        // 监听数据
        observe(data)

        // 测试
        // data.name = 'YI' // (监听成功)输出 --> 数据更新
        // data.age = { num: 21 }  
        // data.information.tel = '13456xxx234' 
        // data.age.num = 110 

    </script>
</body>

</html>